from __future__ import annotations

import json
import os
import time
from typing import Any
import logging

logger = logging.getLogger("reinvent")


def create_extra_parameters(filename: str, parameters: dict[str, Any]) -> None:
    """Creates a JSON file with additional maize workflow parameters"""
    with open(filename, "w", encoding="utf-8") as flow:
        json.dump(parameters, flow, indent=4)


def prepare_input_json(filename: str, smilies: list[str], step_id: int) -> None:
    """Prepare JSON ReinventEntry node input"""
    # Metadata entry reserved for later
    data = {"smiles": smilies, "metadata": {"iteration": step_id}}

    with open(filename, "w", encoding="utf-8") as inp:
        inp.write(json.dumps(data))


def wait_for_output(filename: str, sleep_for: float = 3) -> dict:
    """Wait for output to be generated by Maize

    :param filename: the JSON file name
    :param sleep_for: time to wait before reading from JSON file
    :returns: the JSON dict
    :raises ValueError: if the file is missing or empty
    """

    while not os.path.isfile(filename) or os.path.getsize(filename) == 0:
        time.sleep(sleep_for)

    if not os.path.isfile(filename) or os.path.getsize(filename) == 0:
        raise ValueError(f"{__name__}: failed, missing or empty maize JSON output file")

    with open(filename, "r", encoding="utf-8") as jf:
        data = json.load(jf)

    return data


def parse_output(data: dict, key: str) -> list[float]:
    """Parse JSON output from maize's ReinventEXit node

    The "scores" filed is either a dict for multiple scores or a list in
    compatibility mode.

    :param data: the JSON dict
    :param key: the property (score) name
    :returns: list of scores
    """

    if "scores" not in data:
        raise ValueError(f"{__name__}: JSON file does not contain 'scores'")

    scores = data["scores"]

    if isinstance(scores, list):  # compatibility mode
        results = scores
    else:  # dict
        if key not in scores:
            raise ValueError(f"{__name__}: JSON file does not contain score {key}")

        logger.info(f"Known maize scores: {', '.join([key for key in scores])}")
        results = scores[key]

    return results
